﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;

namespace PY
{
	[AddComponentMenu("UI/Head", 30)]
	public class Head : MaskableGraphic
	{
		enum HeadType
		{
			Circle,
			Rect,
			Parallelogram,
			Full,
			Polygon,
			CustomerCircle,
		}

		public override Texture mainTexture
		{
			get
			{
				if (m_Texture == null)
				{
					if (material != null && material.mainTexture != null)
					{
						return material.mainTexture;
					}

					return s_WhiteTexture;
				}

				return m_Texture;
			}
		}

		public Texture texture
		{
			get
			{
				return m_Texture;
			}
			set
			{
				if (m_Texture == value)
					return;

				m_Texture = value;
				SetVerticesDirty();
				SetMaterialDirty();
			}
		}

		public float factor
		{
			get
			{
				return m_Factor;
			}
			set
			{
				if (m_Factor == value)
					return;

				m_Factor = value;
				SetVerticesDirty();
			}
		}
		public Vector2 centerPosition
		{
			get
			{
				return m_CenterPos;
			}
			set
			{
				if (m_CenterPos.Equals(value))
				{
					return;
				}

				m_CenterPos = value;
				SetVerticesDirty();
			}
		}

		public Vector2 textureOriginSize
		{
			get { return m_TextureOriginSize; }
			set
			{
				if (m_TextureOriginSize.Equals(value))
				{
					return;
				}

				m_TextureOriginSize = value;
				SetVerticesDirty();
			}
		}
		public void SetTexture(Texture t)
		{
			m_Texture = t;
		}

		[FormerlySerializedAs("m_Tex")]
		[SerializeField]
		private Texture m_Texture;
		[SerializeField]

		private Vector2 m_CenterPos = new Vector2(0, 0);
		[SerializeField]
		private Vector2 m_TextureOriginSize = new Vector2(613, 1334);
		[SerializeField]
		private HeadType m_HeadType = HeadType.Rect;

		private Vector2Int angleRange = new Vector2Int(0, 360);

		[SerializeField] private float m_Factor = 1.0f;
		[SerializeField] private PolygonCollider2D polygonCollider;
		protected override void OnPopulateMesh(VertexHelper vh)
		{
			//Debug.LogFormat("  ...... OnPopulateMesh : {0} , {1}", this, m_HeadType );
			vh.Clear();
			if (m_Texture == null)
			{
				return;
			}
			switch (m_HeadType)
			{
				case HeadType.Circle:
					CircleMesh(vh);
					break;
				case HeadType.Parallelogram:
					ParallelogramMesh(vh);
					break;
				case HeadType.Rect:
					RectMesh(vh);
					break;
				case HeadType.Full:
					FullMesh(vh);
					break;
				case HeadType.CustomerCircle:
					CustomerCircleMesh(vh);
					break;
			}
		}
		private void CustomerCircleMesh(VertexHelper vh)
		{
			float tw = rectTransform.rect.width;
			float xScale = m_Texture.width / m_TextureOriginSize.x;
			float yScale = m_Texture.height / m_TextureOriginSize.y;
			float x = (m_CenterPos.x * xScale) / m_Texture.width;
			float y = (m_Texture.height - m_CenterPos.y * yScale) / m_Texture.height;
			int segements = 30;
			float fillPercent = 1.0f;
			float degreeDelta = (float)(2 * Mathf.PI / segements);
			int curSegements = (int)(segements * fillPercent);

			float outerRadius = rectTransform.pivot.x * tw;

			float uvScaleX = 1.0f / m_Texture.width * m_Factor;
			float uvScaleY = 1.0f / m_Texture.height * m_Factor;

			float curDegree = 0;
			UIVertex uiVertex;
			int verticeCount;
			int triangleCount;
			Vector2 curVertice;

			curVertice = Vector2.zero;
			verticeCount = curSegements + 1;
			uiVertex = new UIVertex();
			uiVertex.color = color;
			uiVertex.position = curVertice;
			uiVertex.uv0 = new Vector2(curVertice.x * uvScaleX + x, curVertice.y * uvScaleY + y);
			vh.AddVert(uiVertex);

			for (int i = 1; i < verticeCount; i++)
			{
				float cosA = Mathf.Cos(curDegree);
				float sinA = Mathf.Sin(curDegree);
				curVertice = new Vector2(cosA * outerRadius, sinA * outerRadius);
				curDegree += degreeDelta;

				uiVertex = new UIVertex();
				uiVertex.color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f));
				uiVertex.position = curVertice;
				uiVertex.uv0 = new Vector2(curVertice.x * uvScaleX + x, curVertice.y * uvScaleY + y);
				vh.AddVert(uiVertex);
			}

			triangleCount = curSegements * 3;
			for (int i = 0, vIdx = 1; i < triangleCount - 3; i += 3, vIdx++)
			{
				vh.AddTriangle(vIdx, 0, vIdx + 1);
			}
			//首尾顶点相连
			vh.AddTriangle(verticeCount - 1, 0, 1);
		}
		private void CircleMesh(VertexHelper vh)
		{
			float tw = rectTransform.rect.width;
			float xScale = m_Texture.width / m_TextureOriginSize.x;
			float yScale = m_Texture.height / m_TextureOriginSize.y;
			float x = (m_CenterPos.x * xScale) / m_Texture.width;
			float y = (m_Texture.height - m_CenterPos.y * yScale) / m_Texture.height;
			int segements = 30;
			float fillPercent = 1.0f;
			float degreeDelta = (float)(2 * Mathf.PI / segements);
			int curSegements = (int)(segements * fillPercent);

			float outerRadius = rectTransform.pivot.x * tw;

			float uvScaleX = 1.0f / m_Texture.width * m_Factor;
			float uvScaleY = 1.0f / m_Texture.height * m_Factor;

			float curDegree = 0;
			UIVertex uiVertex;
			int verticeCount;
			int triangleCount;
			Vector2 curVertice;

			curVertice = Vector2.zero;
			verticeCount = curSegements + 1;
			uiVertex = new UIVertex();
			uiVertex.color = color;
			uiVertex.position = curVertice;
			uiVertex.uv0 = new Vector2(curVertice.x * uvScaleX + x, curVertice.y * uvScaleY + y);
			vh.AddVert(uiVertex);

			for (int i = 1; i < verticeCount; i++)
			{
				float cosA = Mathf.Cos(curDegree);
				float sinA = Mathf.Sin(curDegree);
				curVertice = new Vector2(cosA * outerRadius, sinA * outerRadius);
				curDegree += degreeDelta;

				uiVertex = new UIVertex();
				uiVertex.color = color;
				uiVertex.position = curVertice;
				uiVertex.uv0 = new Vector2(curVertice.x * uvScaleX + x, curVertice.y * uvScaleY + y);
				vh.AddVert(uiVertex);
			}

			triangleCount = curSegements * 3;
			for (int i = 0, vIdx = 1; i < triangleCount - 3; i += 3, vIdx++)
			{
				vh.AddTriangle(vIdx, 0, vIdx + 1);
			}
			//首尾顶点相连
			vh.AddTriangle(verticeCount - 1, 0, 1);
		}
		private void FullMesh(VertexHelper vh)
		{

			float tw = rectTransform.rect.width;
			float th = rectTransform.rect.height;
			float px = rectTransform.pivot.x;
			float py = rectTransform.pivot.y;
			float tx = px * tw;
			float ty = py * th;
			vh.AddVert(new Vector3(-tx, -ty), color, new Vector2(0, 0));
			vh.AddVert(new Vector3(-tx, ty), color, new Vector2(0, 1));
			vh.AddVert(new Vector3(tx, ty), color, new Vector2(1, 1));
			vh.AddVert(new Vector3(tx, -ty), color, new Vector2(1, 0));
			vh.AddTriangle(0, 1, 2);
			vh.AddTriangle(2, 3, 0);
		}
		private void ParallelogramMesh(VertexHelper vh)
		{
			float tw = rectTransform.rect.width;
			float th = rectTransform.rect.height;
			float xScale = m_Texture.width / m_TextureOriginSize.x;
			float yScale = m_Texture.height / m_TextureOriginSize.y;
			float x = (m_CenterPos.x * xScale) / m_Texture.width;
			float y = (m_Texture.height - m_CenterPos.y * yScale) / m_Texture.height;
			float uvw = tw / m_Texture.width * m_Factor * xScale;
			float uvh = th / m_Texture.height * m_Factor * yScale;

			float px = rectTransform.pivot.x;
			float py = rectTransform.pivot.y;
			float tx = px * tw;
			float ty = py * th;
			float xOffset = tw * 0.2f;
			float offsetuv = xOffset / m_TextureOriginSize.x;

			vh.AddVert(new Vector3(-tx, -ty), color, new Vector2(x - uvw * px, y - uvh * py));
			vh.AddVert(new Vector3(-tx + xOffset, ty), color, new Vector2(x - uvw * px + offsetuv, y + uvh * (1 - py)));
			vh.AddVert(new Vector3(tx, ty), color, new Vector2(x + uvw * (1 - px), y + uvh * (1 - py)));
			vh.AddVert(new Vector3(tx - xOffset, -ty), color, new Vector2(x + uvw * (1 - px) - offsetuv, y - uvh * py));
			vh.AddTriangle(0, 1, 2);
			vh.AddTriangle(2, 3, 0);
		}
		private void RectMesh(VertexHelper vh)
		{
			float tw = rectTransform.rect.width;
			float th = rectTransform.rect.height;
			float xScale = m_Texture.width / m_TextureOriginSize.x;
			float yScale = m_Texture.height / m_TextureOriginSize.y;
			float x = (m_CenterPos.x * xScale) / m_Texture.width;
			float y = (m_Texture.height - m_CenterPos.y * yScale) / m_Texture.height;
			float uvw = tw / m_Texture.width * m_Factor * xScale;
			float uvh = th / m_Texture.height * m_Factor * yScale;

			float px = rectTransform.pivot.x;
			float py = rectTransform.pivot.y;
			float tx = px * tw;
			float ty = py * th;
			float xOffset = 0;
			float offsetuv = 0;
			vh.AddVert(new Vector3(-tx, -ty), color, new Vector2(x - uvw * px, y - uvh * py));
			vh.AddVert(new Vector3(-tx + xOffset, ty), color, new Vector2(x - uvw * px + offsetuv, y + uvh * (1 - py)));
			vh.AddVert(new Vector3(tx, ty), color, new Vector2(x + uvw * (1 - px), y + uvh * (1 - py)));
			vh.AddVert(new Vector3(tx - xOffset, -ty), color, new Vector2(x + uvw * (1 - px) - offsetuv, y - uvh * py));
			vh.AddTriangle(0, 1, 2);
			vh.AddTriangle(2, 3, 0);
		}

		public void UpdateShow(int frameNum = 0)
		{
			//Debug.LogFormat(" .. UpdateShow : {0}, {1}", this, frameNum );
			if (frameNum == 0)
			{
				UpdateGeometry();
			}
			else
			{
				StartCoroutine(RefreshShow(frameNum));
			}
		}
		IEnumerator RefreshShow(int frameNum)
		{
			for (int i = 0; i < frameNum; i++)
			{
				yield return new WaitForEndOfFrame();
				UpdateGeometry();
			}
		}

		private Vector3 scale = Vector3.zero;

		private void Update()
		{
			if (scale == Vector3.zero && gameObject.transform.lossyScale != Vector3.zero && IsPolygon())
			{
				Rebuild(CanvasUpdate.PreRender);
			}
		}

		public bool IsPolygon()
		{
			return m_HeadType == HeadType.Polygon;
		}

		public string GetHeadTypeString()
		{
			return m_HeadType.ToString();
		}
	}
}